extern "C" {
    #[link_name = "printf"]
    pub fn printf_c(format: *const u8, ...) -> i32;
}

#[macro_export]
macro_rules! printf {
    ($fmt:literal $($args:tt)*) => {
        crust::printf_c(concat!($fmt, "\0").as_ptr() $($args)*)
    }
}

pub unsafe fn malloc(size: usize) -> *mut u8 {
    extern "C" {
        #[link_name = "malloc"]
        fn malloc_c(size: usize) -> *mut u8;
    }
    return malloc_c(size);
}

pub unsafe fn malloc_value<T>() -> *mut T {
    malloc(size_of::<T>()) as *mut T
}

pub unsafe fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
    extern "C" {
        #[link_name = "realloc"]
        fn realloc_c(ptr: *mut u8, size: usize) -> *mut u8;
    }
    return realloc_c(ptr, size);
}

pub unsafe fn free(ptr: *mut u8) {
    extern "C" {
        #[link_name = "free"]
        fn free_c(ptr: *mut u8);
    }
    free_c(ptr);
}

pub unsafe fn free_value<T>(ptr: *mut T) {
    free(ptr as *mut u8);
}

pub unsafe fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    extern "C" {
        #[link_name = "memcpy"]
        fn memcpy_c(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    }
    memcpy_c(dest, src, n)
}

pub unsafe fn memcpy_value<T>(dest: *mut T, src: *const T) {
    memcpy(dest as *mut u8, src as *const u8, size_of::<T>());
}

pub unsafe fn exit(status: i32) -> ! {
    extern "C" {
        #[link_name = "exit"]
        fn exit_c(status: i32) -> !;
    }
    exit_c(status);
}
